package com.mall.seckill_mall.service.impl;

import com.mall.seckill_mall.common.RedisPreffix;
import com.mall.seckill_mall.dao.UserDao;
import com.mall.seckill_mall.entity.User;
import com.mall.seckill_mall.enums.CodeMessage;
import com.mall.seckill_mall.exception.UserException;
import com.mall.seckill_mall.service.UserService;
import com.mall.seckill_mall.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

/**
 * @author 最亮的仔
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;

    @Override
    public User getUser(String userId) {
        String redisKey = RedisPreffix.USER_PREFFIX.concat(userId);
        User user = (User) redisTemplate.opsForValue().get(redisKey);
        if(user == null) {
            user = userDao.selectOne(userId);
            if(user != null) {
                insertUserToRedis(user);
                redisTemplate.expire(redisKey, 5, TimeUnit.SECONDS);
            }

        }
        return user;
    }

    @Override
    public User getUserByToken(String userToken) {
        String redisKey = RedisPreffix.ONLINE_USER_PREFFIX.concat(userToken);
        return (User) redisTemplate.opsForValue().get(redisKey);
    }

    @Override
    public void setUserByToken(String userToken, User user) {
        String redisKey = RedisPreffix.ONLINE_USER_PREFFIX.concat(userToken);
        redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES);
    }

    @Override
    public void deleteUserByToken(String userToken) {
        String redisKey = RedisPreffix.ONLINE_USER_PREFFIX.concat(userToken);
        redisTemplate.delete(redisKey);
    }

    @Override
    public boolean registerUser(User user) {
        User dbUser = getUser(user.getUserId());
        if(dbUser != null) {
            throw new UserException(CodeMessage.USER_EXISTS);
        }
        boolean ok = userDao.insertOne(user) == 1;
        if(ok) {
            insertUserToRedis(user);
        }
        return ok;
    }

    @Override
    public User loginUser(String userId, String userPassWord) {
        User dbUser = getUser(userId);
        if(dbUser == null) {
            throw new UserException(CodeMessage.USER_NOT_EXISTS);
        }
        String md5Password = MD5Util.getMD5(userPassWord);
        if(!md5Password.equals(dbUser.getUserPassWord())) {
            throw new UserException(CodeMessage.USER_PASSWORD_ERROR);
        }
        return dbUser;
    }

    private void insertUserToRedis(User user) {
        String redisKey = RedisPreffix.USER_PREFFIX.concat(user.getUserId());
        redisTemplate.opsForValue().set(redisKey, user, 7L, TimeUnit.DAYS);
    }

    @Override
    public void updatePassWord(String userId, String oldPassWord, String passWord) {
        User dbUser = loginUser(userId, oldPassWord);
        insertUserToRedis(dbUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public double updateBalance(String userId, double balance) {
        User dbUser = getUser(userId);
        if(dbUser == null) {
            throw new UserException(CodeMessage.USER_NOT_EXISTS);
        }
        boolean ok = userDao.updateBalance(userId, balance) == 1;
        if(!ok) {
            throw new UserException(CodeMessage.SERVER_ERROR);
        }
        dbUser = userDao.selectOne(userId);
        redisTemplate.opsForValue().set(RedisPreffix.USER_PREFFIX.concat(userId), dbUser);
        return dbUser.getUserBalance();
    }
}
